package org.west.sky.experience.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NioServer {

    public static void main(String[] args) throws Exception {
        //创建一个选择器
        Selector selector = Selector.open();
        //创建serverSelectChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //绑定端口
        serverSocketChannel.socket().bind(new InetSocketAddress(4444));
        //设置非阻塞
        serverSocketChannel.configureBlocking(false);
        //注册选择器
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("NIO 服务端启动================");
        while (true) {
            //阻塞等待
            if (selector.select(1000) == 0) {
                System.out.println("NIO 服务端超时等待============");
                continue;
            }
            //获取选择器中注册的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                //判断是否是accept事件
                if (key.isAcceptable()) {
                    //处理接收请求事件
                    SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
                    //设置非阻塞
                    socketChannel.configureBlocking(false);
                    //注册到Selector并设置监听事件为READ
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                    System.out.println("成功连接客户端");
                }
                //判断是否是读事件
                if (key.isReadable()) {
                    //处理读事件
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    try {
                        //获取读缓冲区
                        ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
                        if (byteBuffer == null) {
                            byteBuffer = ByteBuffer.allocate(1024);
                        }
                        byteBuffer.clear();
                        //读取数据
                        int read = socketChannel.read(byteBuffer);
                        if (read > 0) {
                            byteBuffer.flip();
                            String content = new String(byteBuffer.array(), 0, read);
                            System.out.println("客户端发送数据:" + content);
                        } else if (read < 0) {
                            //接收到的字节小于0，说明客户端关闭了连接
                            key.cancel();
                            socketChannel.close();
                            continue;
                        }
                        //注册写事件，下次向客户端发送消息
                        socketChannel.register(selector, SelectionKey.OP_WRITE, byteBuffer);
                    } catch (IOException e) {
                        //取消SelectorKey并关相对应的SocketChannel
                        key.cancel();
                        socketChannel.close();
                    }
                }
                //判断是否是写事件
                if (key.isWritable()) {
                    SocketChannel socketChannel = (SocketChannel) key.channel();

                    //获取写缓冲区
                    ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
                    String hello = "hello client";
                    //清空缓冲区
                    byteBuffer.clear();
                    //buffer中写入数据
                    byteBuffer.put(hello.getBytes());
                    byteBuffer.flip();
                    //写数据
                    socketChannel.write(byteBuffer);
                    byteBuffer.clear();
                    System.out.println("向客户端发送数据:" + hello);
                    //设置下次读写操作，向Selector注册事件
                    socketChannel.register(selector, SelectionKey.OP_READ, byteBuffer);
                }
                iterator.remove();
            }
        }
    }
}
